home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 4 / Apprentice-Release4.iso / Source Code / Libraries / SAT 2.3.7 / Add-ons / Sprite behavior / SATGridToolbox.p < prev    next >
Encoding:
Text File  |  1995-09-10  |  10.9 KB  |  349 lines  |  [TEXT/PJMM]

  1. {SATGridToolbox}
  2. {}
  3. {Routines for SAT-based games with a game world defined by a grid.}
  4. {Note that this is the "Oxyd"-style world, where movement isn't contrained to the grid,}
  5. {but obstacles etc are defined by it. It is NOT ment for strict grid movement, as in PacMan!}
  6. {}
  7. {Limitations and assumptions:}
  8. {• Your grid is defined in the unit SATGridStubs.}
  9. {• All free space grid values are smaller than the blocked ones. (Specified by kFreeSpace.) }
  10. {• Sprites should not be bigger (wider/higher) than the grid spaces. (Sprites only check with the}
  11. {corners of the hotRects, which mens that a small grid obstacle could pass right through it!)}
  12. {}
  13. {Idéer:}
  14. {• Lägg till rutiner för förflyttning och kollisionshantering i strikt grid. Eller skall det vara en}
  15. {egen modul?}
  16. {• Duger LoadGrid?}
  17. {• Prefix på namnen?}
  18.  
  19. unit SATGridToolbox;
  20.  
  21. interface
  22.  
  23.     uses
  24. {$IFC UNDEFINED THINK_PASCAL}
  25.         Types, QuickDraw, Fonts, Events, Packages, Menus, Dialogs, Windows,{}
  26.         OSUtils, ToolUtils, {OSEvents,} Resources,
  27. {$ENDC}
  28.         SAT, SATToolbox, SATGridStubs;
  29.  
  30.     procedure MoveSpriteInGrid (theSprite: FixSpritePtr);
  31. {procedure HitSprite (theSprite: FixSpritePtr; anotherSprite: FixSpritePtr); SKIT?}
  32.     function Pt2GridValue (p: Point): GridSpaceType;
  33.     procedure LoadGrid (resNum: Integer);
  34.     procedure DrawAllTiles;
  35.     function PtInGrid (p: Point): Boolean;
  36.  
  37. implementation
  38.  
  39. {Load the grid from a TEXT resource.}
  40.     procedure LoadGrid (resNum: Integer);
  41.         type
  42.             CharArr = packed array[0..99999] of Char;
  43.             CharArrPtr = ^CharArr;
  44.             CharArrHnd = ^CharArrPtr;
  45.         var
  46.             hnd: CharArrHnd;
  47.             howMuch: Longint;
  48.             h, v: Integer;
  49.     begin
  50.         hnd := CharArrHnd(GetResource('TEXT', resNum));
  51.         if hnd = nil then
  52.             exit(LoadGrid);
  53.         if GetHandleSize(Handle(hnd)) > SizeOf(tileArray) then
  54.             howMuch := SizeOf(tileArray)
  55.         else
  56.             howMuch := GetHandleSize(Handle(hnd));
  57.  
  58.         HLock(Handle(hnd));
  59.  
  60.         h := 0;
  61.         v := 0;
  62.         howMuch := 0;
  63.  
  64.         while howMuch < GetHandleSize(Handle(hnd)) do
  65.             begin
  66.                 if hnd^^[howMuch] = Char(13) then
  67.                     begin
  68.                         h := 0;
  69.                         v := v + 1;
  70.                     end
  71.                 else
  72.                     begin
  73.                         if h < kArraySizeH then
  74.                             if v < kArraySizeV then
  75.                                 tileArray[h, v] := hnd^^[howMuch];
  76.                         h := h + 1;
  77.                     end;
  78.  
  79.                 howMuch := howMuch + 1;
  80.             end;
  81.  
  82.         HUnLock(Handle(hnd));
  83.  
  84. {BlockMove(Ptr(hnd^), @tileArray[0, 0], howMuch);}
  85.         ReleaseResource(Handle(hnd));
  86.     end; {LoadGrid}
  87.  
  88. {PtInGrid: is the point blocked or free?}
  89. {Needs improving: several different grid values should be free!}
  90.  
  91.     function PtInGrid (p: Point): Boolean;
  92.     begin
  93.         PtInGrid := tileArray[p.h div kTileSizeH][p.v div kTileSizeV] > kFreeSpace;
  94.     end; (*PtInGrid*)
  95.  
  96.  
  97. {Get the grid value in a point. A sprite can, for example, test with its center!}
  98.  
  99.     function Pt2GridValue (p: Point): GridSpaceType;
  100.     begin
  101.         Pt2GridValue := tileArray[p.h div kTileSizeH][p.v div kTileSizeV];
  102.     end; (*Pt2GridValue*)
  103.  
  104.     procedure GetGridRect (p: Point; var r: Rect);
  105.     begin
  106.         SetRect(r, p.h div kTileSizeH * kTileSizeH, p.v div kTileSizeV * kTileSizeV, (p.h div kTileSizeH + 1) * kTileSizeH, (p.v div kTileSizeV + 1) * kTileSizeV);
  107.     end; (*GetGridRect*)
  108.  
  109.     function RectSeparateRect (theSprite: SpritePtr; var anotherRect: Rect): Integer;
  110.         var
  111.             distance: array[0..3] of Integer;
  112.             shortest, shortestDistance, i: Integer;
  113.             bounds1, bounds2: Rect;
  114.     begin
  115.         bounds1 := theSprite^.hotRect;
  116.         OffsetRect(bounds1, theSprite^.position.h, theSprite^.position.v);
  117.  
  118.         bounds2 := anotherRect;
  119.  
  120. (*Calculate the distance to separate the sprites in every direction*)
  121.         distance[0] := bounds2.top - bounds1.bottom; {up}
  122.         distance[1] := bounds2.bottom - bounds1.top; {down}
  123.         distance[2] := bounds2.right - bounds1.left; {right}
  124.         distance[3] := bounds2.left - bounds1.right; {left}
  125.  
  126. (*Find the shortest distance*)
  127.         shortest := 0;
  128.         shortestDistance := abs(distance[0]);
  129.         for i := 1 to 3 do
  130.             if abs(distance[i]) < shortestDistance then
  131.                 begin
  132.                     shortest := i;
  133.                     shortestDistance := abs(distance[i]);
  134.                 end;
  135.  
  136. (*Move the sprite in the appropriate direction*)
  137.         case shortest of
  138.             0, 1: 
  139.                 theSprite^.position.v := theSprite^.position.v + distance[shortest];
  140.             2, 3: 
  141.                 theSprite^.position.h := theSprite^.position.h + distance[shortest];
  142.         end; {case}
  143.         RectSeparateRect := shortest;
  144.     end; (*RectSeparateRect*)
  145.  
  146.  
  147. {GridTest: A complex function that tests whether a sprite is in free space or not, and bounces}
  148. {off grid obstacles if not.}
  149.  
  150.     procedure GridTest (theSprite: FixSpritePtr);
  151.         var
  152.             p1, p2, p3, p4: Point;
  153.             bounds, gridRect: Rect;
  154.             sum: Integer;
  155.     begin
  156.         sum := 0;
  157.         bounds := theSprite^.hotRect;
  158.         OffsetRect(bounds, theSprite^.position.h, theSprite^.position.v);
  159.         p1 := bounds.topLeft;
  160.         p2.h := bounds.left;
  161.         p2.v := bounds.bottom;
  162.         p3.h := bounds.right;
  163.         p3.v := bounds.top;
  164.         p4 := bounds.botRight;
  165.  
  166.         if PtInGrid(p1) then
  167.             sum := sum + 1;
  168.         if PtInGrid(p2) then
  169.             sum := sum + 2;
  170.         if PtInGrid(p3) then
  171.             sum := sum + 4;
  172.         if PtInGrid(p4) then
  173.             sum := sum + 8;
  174.  
  175.         case sum of
  176.             0, 15: 
  177.                 Exit(GridTest);
  178. { Single corner}
  179.             1: 
  180.                 begin
  181.                     GetGridRect(p1, gridRect);
  182.                     if RectSeparateRect(SpritePtr(theSprite), gridRect) >= 2 then
  183.                         theSprite^.speed.h := abs(theSprite^.speed.h)
  184.                     else
  185.                         theSprite^.speed.v := abs(theSprite^.speed.v);
  186.                 end;
  187.             2: 
  188.                 begin
  189.                     GetGridRect(p2, gridRect);
  190.                     if RectSeparateRect(SpritePtr(theSprite), gridRect) >= 2 then
  191.                         theSprite^.speed.h := abs(theSprite^.speed.h)
  192.                     else
  193.                         theSprite^.speed.v := -abs(theSprite^.speed.v);
  194.                 end;
  195.             4: 
  196.                 begin
  197.                     GetGridRect(p3, gridRect);
  198.                     if RectSeparateRect(SpritePtr(theSprite), gridRect) >= 2 then
  199.                         theSprite^.speed.h := -abs(theSprite^.speed.h)
  200.                     else
  201.                         theSprite^.speed.v := abs(theSprite^.speed.v);
  202.                 end;
  203.             8: 
  204.                 begin
  205.                     GetGridRect(p4, gridRect);
  206.                     if RectSeparateRect(SpritePtr(theSprite), gridRect) >= 2 then
  207.                         theSprite^.speed.h := -abs(theSprite^.speed.h)
  208.                     else
  209.                         theSprite^.speed.v := -abs(theSprite^.speed.v);
  210.                 end;
  211. { Sides}
  212.             3: {left}
  213.                 begin
  214.                     theSprite^.position.h := (p1.h div kTileSizeH + 1) * kTileSizeH;
  215.                     theSprite^.speed.h := abs(theSprite^.speed.h);
  216.                 end;
  217.             5: { top}
  218.                 begin
  219.                     theSprite^.position.v := (p1.v div kTileSizeV + 1) * kTileSizeV;
  220.                     theSprite^.speed.v := abs(theSprite^.speed.v);
  221.                 end;
  222.             10: { bottom}
  223.                 begin
  224.                     theSprite^.position.v := (p4.v div kTileSizeV + 0) * kTileSizeV - theSprite^.hotRect.bottom;
  225.                     theSprite^.speed.v := -abs(theSprite^.speed.v);
  226.                 end;
  227.             12: { right}
  228.                 begin
  229.                     theSprite^.position.h := (p4.h div kTileSizeH + 0) * kTileSizeH - theSprite^.hotRect.right;
  230.                     theSprite^.speed.h := -abs(theSprite^.speed.h);
  231.                 end;
  232.  
  233. { three corners}
  234.             7: {bottom right free}
  235.                 begin
  236.                     theSprite^.position.h := (p1.h div kTileSizeH + 1) * kTileSizeH;
  237.                     theSprite^.speed.h := abs(theSprite^.speed.h);
  238.                     theSprite^.position.v := (p1.v div kTileSizeV + 1) * kTileSizeV;
  239.                     theSprite^.speed.v := abs(theSprite^.speed.v);
  240.                 end;
  241.             11: { top right free}
  242.                 begin
  243.                     theSprite^.position.h := (p1.h div kTileSizeH + 1) * kTileSizeH;
  244.                     theSprite^.speed.h := abs(theSprite^.speed.h);
  245.                     theSprite^.position.v := (p4.v div kTileSizeV + 0) * kTileSizeV - theSprite^.hotRect.bottom;
  246.                     theSprite^.speed.v := -abs(theSprite^.speed.v);
  247.                 end;
  248.             13: { bottom left free}
  249.                 begin
  250.                     theSprite^.position.h := (p4.h div kTileSizeH + 0) * kTileSizeH - theSprite^.hotRect.right;
  251.                     theSprite^.speed.h := -abs(theSprite^.speed.h);
  252.                     theSprite^.position.v := (p1.v div kTileSizeV + 1) * kTileSizeV;
  253.                     theSprite^.speed.v := abs(theSprite^.speed.v);
  254.                 end;
  255.             14: { top left free}
  256.                 begin
  257.                     theSprite^.position.h := (p4.h div kTileSizeH + 0) * kTileSizeH - theSprite^.hotRect.right;
  258.                     theSprite^.speed.h := -abs(theSprite^.speed.h);
  259.                     theSprite^.position.v := (p4.v div kTileSizeV + 0) * kTileSizeV - theSprite^.hotRect.bottom;
  260.                     theSprite^.speed.v := -abs(theSprite^.speed.v);
  261.                 end;
  262.             6: { diagonal}
  263.                 begin
  264.                     if theSprite^.speed.h + theSprite^.speed.v > 0 then { if down-right speed}
  265.                         begin
  266.                             theSprite^.position.h := (p4.h div kTileSizeH + 0) * kTileSizeH - theSprite^.hotRect.right;
  267.                             theSprite^.speed.h := -abs(theSprite^.speed.h);
  268.                             theSprite^.position.v := (p4.v div kTileSizeV + 0) * kTileSizeV - theSprite^.hotRect.bottom;
  269.                             theSprite^.speed.v := -abs(theSprite^.speed.v);
  270.                         end
  271.                     else { else up-left speed}
  272.                         begin
  273.                             theSprite^.position.h := (p1.h div kTileSizeH + 1) * kTileSizeH;
  274.                             theSprite^.speed.h := abs(theSprite^.speed.h);
  275.                             theSprite^.position.v := (p1.v div kTileSizeV + 1) * kTileSizeV;
  276.                             theSprite^.speed.v := abs(theSprite^.speed.v);
  277.                         end;
  278.                 end;
  279.             9: { diagonal}
  280.                 begin
  281.                     if theSprite^.speed.h - theSprite^.speed.v > 0 then { if up-right speed}
  282.                         begin
  283.                             theSprite^.position.h := (p4.h div kTileSizeH + 0) * kTileSizeH - theSprite^.hotRect.right;
  284.                             theSprite^.speed.h := -abs(theSprite^.speed.h);
  285.                             theSprite^.position.v := (p1.v div kTileSizeV + 1) * kTileSizeV;
  286.                             theSprite^.speed.v := abs(theSprite^.speed.v);
  287.                         end
  288.                     else { else down-left speed}
  289.                         begin
  290.                             theSprite^.position.h := (p4.h div kTileSizeH + 0) * kTileSizeH - theSprite^.hotRect.right;
  291.                             theSprite^.speed.h := -abs(theSprite^.speed.h);
  292.                             theSprite^.position.v := (p1.v div kTileSizeV + 1) * kTileSizeV;
  293.                             theSprite^.speed.v := abs(theSprite^.speed.v);
  294.                         end;
  295.                 end;
  296.         end; {case}
  297.         theSprite^.fixedPointPosition.h := BSL(theSprite^.position.h, 4);
  298.         theSprite^.fixedPointPosition.v := BSL(theSprite^.position.v, 4);
  299.     end; (*GridTest*)
  300.  
  301.     var
  302.         firstFace, secondFace, thirdFace: GrafPtr;
  303.  
  304.     procedure MoveSpriteInGrid (theSprite: FixSpritePtr);
  305. {    theSprite->speed.v++; // Simple gravity}
  306.     begin
  307.         theSprite^.fixedPointPosition.h := theSprite^.fixedPointPosition.h + theSprite^.speed.h;
  308.         theSprite^.fixedPointPosition.v := theSprite^.fixedPointPosition.v + theSprite^.speed.v;
  309.         theSprite^.position.h := BSR(theSprite^.fixedPointPosition.h, 4);
  310.         theSprite^.position.v := BSR(theSprite^.fixedPointPosition.v, 4);
  311.         GridTest(theSprite);
  312.         if KeepOnScreenFixed(theSprite) then
  313.             ;
  314.     end; (*MoveSpriteInGrid*)
  315.  
  316.  
  317. {Standard rect-based bounce-off collision handling.}
  318. {VAD ÄR DETTA FÖR SKIT???}
  319.     procedure HitSprite (theSprite: FixSpritePtr; anotherSprite: FixSpritePtr);
  320.         var
  321.             tempSpeed: Integer;
  322.     begin
  323.         if RectSeparate(SpritePtr(theSprite), SpritePtr(anotherSprite), kPushBoth) >= 2 then { 2 or 3: horizontal, otherwise vertical}
  324.             begin
  325.                 tempSpeed := theSprite^.speed.h;
  326.                 theSprite^.speed.h := anotherSprite^.speed.h;
  327.                 anotherSprite^.speed.h := tempSpeed;
  328.                 theSprite^.fixedPointPosition.h := BSL(theSprite^.position.h, 4);
  329.             end
  330.         else
  331.             begin
  332.                 tempSpeed := theSprite^.speed.v;
  333.                 theSprite^.speed.v := anotherSprite^.speed.v;
  334.                 anotherSprite^.speed.v := tempSpeed;
  335.                 theSprite^.fixedPointPosition.v := BSL(theSprite^.position.v, 4);
  336.             end;
  337.     end; (*HitSprite*)
  338.  
  339.  
  340.     procedure DrawAllTiles;
  341.         var
  342.             h, v: Integer;
  343.     begin
  344.         for h := 0 to kArraySizeH - 1 do
  345.             for v := 0 to kArraySizeV - 1 do
  346.                 DrawTile(h, v);
  347.     end; {DrawAllTiles}
  348.  
  349. end.